/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "libzlang_network.h"

#include "hetao_api.h"

#include "fastertpl.h"

#define MAX_DIR_ARRAY		16

struct MatchingUriDirectory
{
	char	*dir_name ;
	int	dir_name_len ;
} ;

struct MatchingUriFunctionCache
{
	struct MatchingUriDirectory	dir_array[ MAX_DIR_ARRAY ] ;
	int				dir_count ;
	struct ZlangFunction		*func ;
	
	struct list_head		matching_uri_func_cache_list_node ;
} ;

struct HtmlTemplate
{
	char				*pathfilename ;
	struct FasterTempate		*tpl ;
	
	struct rb_node			html_tpl_treenode ;
} ;

struct ZlangDirectProperty_httpserver
{
	char				ip[ 40 + 1 ] ;
	int32_t				port ;
	
	char				domain[ 256 + 1 ] ;
	char				wwwroot[ 256 + 1 ] ;
	char				index[ 256 + 1 ] ;
	char				socgi_type[ 32 + 1 ] ;
	unsigned char			disable_x_forwarded_for ;
	
	char				access_log[ 256 + 1 ] ;
	char				error_log[ 256 + 1 ] ;
	
	int32_t				worker_processes ;
	
	struct HttpApplicationContext	*ctx ;
	
	struct HttpBuffer		*http_rsp_headers_buf ;
	struct HttpBuffer		*http_rsp_body_buf ;
	
	unsigned char			init_matching_uri_func_cache_flag ;
	struct list_head		get_matching_uri_func_cache_list ;
	struct list_head		post_matching_uri_func_cache_list ;
	struct list_head		put_matching_uri_func_cache_list ;
	struct list_head		patch_matching_uri_func_cache_list ;
	struct list_head		delete_matching_uri_func_cache_list ;
	
	struct rb_root			html_tpl_tree ;
} ;

int LinkHtmlTemplateToTreeByPathfilename( struct ZlangDirectProperty_httpserver *prop , struct HtmlTemplate *html_tpl );
void UnlinkHtmlTemplateFromTree( struct ZlangDirectProperty_httpserver *prop , struct HtmlTemplate *html_tpl );
struct HtmlTemplate *QueryHtmlTemplateInTreeByPathfilename( struct ZlangDirectProperty_httpserver *prop , struct HtmlTemplate *html_tpl );
struct HtmlTemplate *TravelHtmlTemplateInTreeByPathfilename( struct ZlangDirectProperty_httpserver *pro , struct HtmlTemplate *html_tpl );
void DestroyHtmlTemplateTree( struct ZlangDirectProperty_httpserver *prop );

static void FreeHtmlTemplate( void *pv )
{
	struct HtmlTemplate		*html_tpl = (struct HtmlTemplate *) pv ;
	
	if( html_tpl )
	{
		if( html_tpl->pathfilename )
		{
			ZLFREE( html_tpl->pathfilename ); html_tpl->pathfilename = NULL ;
		}
		
		if( html_tpl->tpl )
		{
			FTDestroyTemplate( html_tpl->tpl ); html_tpl->tpl = NULL ;
		}
		
		ZLFREE( html_tpl );
	}
	
	return;
}

LINK_RBTREENODE_STRING( LinkHtmlTemplateToTreeByPathfilename , struct ZlangDirectProperty_httpserver , html_tpl_tree , struct HtmlTemplate , html_tpl_treenode , pathfilename )
UNLINK_RBTREENODE( UnlinkHtmlTemplateFromTree , struct ZlangDirectProperty_httpserver , html_tpl_tree , struct HtmlTemplate , html_tpl_treenode )
QUERY_RBTREENODE_STRING( QueryHtmlTemplateInTreeByPathfilename , struct ZlangDirectProperty_httpserver , html_tpl_tree , struct HtmlTemplate , html_tpl_treenode , pathfilename )
TRAVEL_RBTREENODE( TravelHtmlTemplateInTreeByPathfilename , struct ZlangDirectProperty_httpserver , html_tpl_tree , struct HtmlTemplate , html_tpl_treenode )
DESTROY_RBTREE( DestroyHtmlTemplateTree , struct ZlangDirectProperty_httpserver , html_tpl_tree , struct HtmlTemplate , html_tpl_treenode , FreeHtmlTemplate )

static struct ZlangDirectFunctions direct_funcs_httpserver ;

#include "hetao_socgi.h"

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestIp;
int ZlangInvokeFunction_GetHttpRequestIp( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char					*ip = NULL ;
	char					*p = NULL ;
	int					len ;
	int32_t					ip_len ;
	
	if( httpserver_direct_prop->disable_x_forwarded_for == 0 )
	{
		ip = SOCGIQueryHttpHeaderPtr( httpserver_direct_prop->ctx , "X-Forwarded-For" , & len ) ;
		if( ip == NULL )
			goto _GOTO_GET_IP;
		
		p = memchr( ip , ',' , len ) ;
		if( p )
			len = p - ip ;
	}
	else
	{
_GOTO_GET_IP :
		ip = SOCGIGetIpPtr( httpserver_direct_prop->ctx , & len ) ;
		if( ip == NULL )
		{
			UnreferObject( rt , out1 );
			return 0;
		}
	}
	
	ip_len = len ;
	CallRuntimeFunction_string_SetStringValue( rt , out1 , ip , ip_len );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestMethod;
int ZlangInvokeFunction_GetHttpRequestMethod( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char					*method = NULL ;
	int32_t					method_len ;
	
	method = SOCGIGetHttpHeaderPtr_METHOD( httpserver_direct_prop->ctx , & method_len ) ;
	if( method == NULL )
	{
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_SetStringValue( rt , out1 , method , method_len );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestUri;
int ZlangInvokeFunction_GetHttpRequestUri( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char					*uri = NULL ;
	int32_t					uri_len ;
	
	uri = SOCGIGetHttpHeaderPtr_URI( httpserver_direct_prop->ctx , & uri_len ) ;
	if( uri == NULL )
	{
		UnreferObject( rt , out1 );
		return 0;
	}
	
	CallRuntimeFunction_string_SetStringValue( rt , out1 , uri , uri_len );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestUriPath;
int ZlangInvokeFunction_GetHttpRequestUriPath( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*uri = NULL ;
	int					uri_len ;
	int32_t					index ;
	int					i ;
	char					*p1 = NULL ;
	char					*p2 = NULL ;
	char					*uri_over_end ;
	
	CallRuntimeFunction_int_GetIntValue( rt , in1 , & index );
	if( index < 1 )
	{
		UnreferObject( rt , out1 );
		return 0;
	}
	
	uri = SOCGIGetHttpHeaderPtr_URI( httpserver_direct_prop->ctx , & uri_len ) ;
	if( uri == NULL )
	{
		UnreferObject( rt , out1 );
		return 0;
	}
	
	uri_over_end = uri + uri_len ;
	
	p2 = uri ;
	for( i = 1 ; i <= index ; i++ )
	{
		if( p2 == uri_over_end )
		{
			UnreferObject( rt , out1 );
			return 0;
		}
		
		p1 = p2 + 1 ;
		p2 = memchr( p1 , '/' , uri_len-(p1-uri) ) ;
		if( p2 == NULL )
			p2 = uri_over_end ;
	}
	
	CallRuntimeFunction_string_SetStringValue( rt , out1 , p1 , p2-p1 );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequest;
int ZlangInvokeFunction_GetHttpRequest( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char					*http_request = NULL ;
	int32_t					http_request_len ;
	
	http_request = SOCGIGetHttpBodyPtr( httpserver_direct_prop->ctx , & http_request_len ) ;
	CallRuntimeFunction_string_SetStringValue( rt , out1 , http_request , http_request_len );
	return 0;
}

static int EscapeFold( struct ZlangRuntime *rt , struct ZlangObject *str_obj )
{
	char		**buf = NULL ;
	int32_t		*buf_len = NULL ;
	int32_t		pro_len ;
	char		*p1 = NULL ;
	char		*p2 = NULL ;
	unsigned char	uch1 ;
	unsigned char	uch2 ;
	unsigned char	uch ;
	int		nret = 0 ;
	
	nret = CallRuntimeFunction_string_GetDirectPropertiesPtr( rt , str_obj , & buf , NULL , & buf_len ) ;
	if( nret )
		return nret;
	
	pro_len = 0 ;
	for( ; pro_len <= (*buf_len) ; )
	{
		if( *((*buf)+pro_len) == '%' )
		{
			/*
				A%25B
				 pro_len
				  1
				   2
			*/
			
			p1 = (*buf) + pro_len + 1 ;
			p2 = (*buf) + pro_len + 2 ;
			
			if( '0' <= (*p1) && (*p1) <= '9' )
				uch1 = (*p1) - '0' ;
			else if( 'a' <= (*p1) && (*p1) <= 'f' )
				uch1 = (*p1) - 'a' + 10 ;
			else if( 'A' <= (*p1) && (*p1) <= 'F' )
				uch1 = (*p1) - 'A' + 10 ;
			else
				return -1;
			
			if( '0' <= (*p2) && (*p2) <= '9' )
				uch2 = (*p2) - '0' ;
			else if( 'a' <= (*p2) && (*p2) <= 'f' )
				uch2 = (*p2) - 'a' + 10 ;
			else if( 'A' <= (*p2) && (*p2) <= 'F' )
				uch2 = (*p2) - 'A' + 10 ;
			else
				return -2;
			
			uch = (uch1<<4) + uch2 ;
			*((*buf)+pro_len) = uch ;
			memmove( (*buf)+pro_len+1 , (*buf)+pro_len+3 , (*buf_len)-(pro_len+2) );
			(*buf_len) -= 2 ;
		}
		
		pro_len++;
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestUriParameters;
int ZlangInvokeFunction_GetHttpRequestUriParameters( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*uri = NULL ;
	int32_t					uri_len ;
	char					*uri_parameters = NULL ;
	int32_t					uri_parameters_len ;
	
	char					*key = NULL ;
	int32_t					key_len ;
	struct ZlangObject			*key_obj = NULL ;
	char					*value = NULL ;
	int32_t					value_len ;
	struct ZlangObject			*value_obj = NULL ;
	char					*p = NULL ;
	
	int					nret = 0 ;
	
	uri = SOCGIGetHttpHeaderPtr_URI( httpserver_direct_prop->ctx , & uri_len ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIGetHttpHeaderPtr_URI uri[%.*s]" , uri_len,uri )
	uri_parameters = memchr( uri , '?' , uri_len ) ;
	if( uri_parameters == NULL )
	{
		return 0;
	}
	
	uri_parameters++;
	uri_parameters_len = uri_len - ( uri_parameters - uri ) ;
	uri_parameters = ZLSTRNDUP( uri_parameters , uri_parameters_len ) ;
	if( uri_parameters == NULL )
	{
		UnreferObject( rt , out1 );
		return ZLANG_ERROR_ALLOC;
	}
	
	p = uri_parameters ;
	for( ; ; )
	{
		for( key = p , key_len = 0 ; uri_parameters_len > 0 ; p++ , key_len++ , uri_parameters_len-- )
		{
			if( (*p) == '=' )
				break;
		}
		if( uri_parameters_len == 0 )
		{
			UnreferObject( rt , out1 );
			ZLFREE( uri_parameters );
			return ZLANG_ERROR_INVOKE_METHOD_RETURN;
		}
		
		p++; uri_parameters_len--;
		
		for( value = p , value_len = 0 ; uri_parameters_len > 0 ; p++ , value_len++ , uri_parameters_len-- )
		{
			if( (*p) == '&' )
				break;
		}
		
		key_obj = CloneStringObject( rt , NULL ) ;
		if( key_obj == NULL )
		{
			UnreferObject( rt , out1 );
			ZLFREE( uri_parameters );
			return ZLANG_ERROR_ALLOC;
		}
		CallRuntimeFunction_string_SetStringValue( rt , key_obj , key , key_len );
		EscapeFold( rt , key_obj );
		
		value_obj = CloneStringObject( rt , NULL ) ;
		if( value_obj == NULL )
		{
			UnreferObject( rt , out1 );
			ZLFREE( uri_parameters );
			return ZLANG_ERROR_ALLOC;
		}
		CallRuntimeFunction_string_SetStringValue( rt , value_obj , value , value_len );
		EscapeFold( rt , value_obj );
		
		nret = CallRuntimeFunction_map_Put( rt , out1 , key_obj , value_obj , NULL ) ;
		if( nret )
		{
			UnreferObject( rt , out1 );
			ZLFREE( uri_parameters );
			return ZLANG_ERROR_ALLOC;
		}
		
		if( uri_parameters_len == 0 )
			break;
		
		p++; uri_parameters_len--;
	}
	
	ZLFREE( uri_parameters );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestPost;
int ZlangInvokeFunction_GetHttpRequestPost( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*http_request = NULL ;
	int32_t					http_request_len ;
	
	char					*key = NULL ;
	int32_t					key_len ;
	struct ZlangObject			*key_obj = NULL ;
	char					*value = NULL ;
	int32_t					value_len ;
	struct ZlangObject			*value_obj = NULL ;
	char					*p = NULL ;
	
	int					nret = 0 ;
	
	http_request = SOCGIGetHttpBodyPtr( httpserver_direct_prop->ctx , & http_request_len ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIGetHttpBodyPtr post data[%.*s]" , http_request_len,http_request )
	
	http_request = ZLSTRNDUP( http_request , http_request_len ) ;
	if( http_request == NULL )
	{
		UnreferObject( rt , out1 );
		return ZLANG_ERROR_ALLOC;
	}
	
	p = http_request ;
	for( ; ; )
	{
		for( key = p , key_len = 0 ; http_request_len > 0 ; p++ , key_len++ , http_request_len-- )
		{
			if( (*p) == '=' )
				break;
		}
		if( http_request_len == 0 )
		{
			UnreferObject( rt , out1 );
			ZLFREE( http_request );
			return ZLANG_ERROR_INVOKE_METHOD_RETURN;
		}
		
		p++; http_request_len--;
		
		for( value = p , value_len = 0 ; http_request_len > 0 ; p++ , value_len++ , http_request_len-- )
		{
			if( (*p) == '&' )
				break;
		}
		
		key_obj = CloneStringObject( rt , NULL ) ;
		if( key_obj == NULL )
		{
			UnreferObject( rt , out1 );
			ZLFREE( http_request );
			return ZLANG_ERROR_ALLOC;
		}
		CallRuntimeFunction_string_SetStringValue( rt , key_obj , key , key_len );
		EscapeFold( rt , key_obj );
		CallRuntimeFunction_string_GetStringValue( rt , key_obj , & key , & key_len );
		
		value_obj = CloneStringObject( rt , NULL ) ;
		if( value_obj == NULL )
		{
			UnreferObject( rt , out1 );
			ZLFREE( http_request );
			return ZLANG_ERROR_ALLOC;
		}
		CallRuntimeFunction_string_SetStringValue( rt , value_obj , value , value_len );
		EscapeFold( rt , value_obj );
		CallRuntimeFunction_string_GetStringValue( rt , value_obj , & value , & value_len );
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CallRuntimeFunction_map_Put post item[%.*s][%.*s]" , key_len,key , value_len,value )
		nret = CallRuntimeFunction_map_Put( rt , out1 , key_obj , value_obj , NULL ) ;
		if( nret )
		{
			UnreferObject( rt , out1 );
			ZLFREE( http_request );
			return ZLANG_ERROR_ALLOC;
		}
		
		if( http_request_len == 0 )
			break;
		
		p++; http_request_len--;
	}
	
	ZLFREE( http_request );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_GetHttpRequestCookies;
int ZlangInvokeFunction_GetHttpRequestCookies( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	struct HttpHeader			*p_header = NULL ;
	char					*cookie = NULL ;
	int32_t					cookie_len ;
	char					*p = NULL ;
	char					*key = NULL ;
	int32_t					key_len ;
	struct ZlangObject			*key_obj = NULL ;
	char					*value = NULL ;
	int32_t					value_len ;
	struct ZlangObject			*value_obj = NULL ;
	
	int					nret = 0 ;
	
	p_header = NULL ;
	while( ( p_header = SOCGITravelHttpHeaderPtr( httpserver_direct_prop->ctx , p_header ) ) )
	{
		cookie = SOCGIGetHttpHeaderNamePtr( p_header , & cookie_len ) ;
		if( cookie_len == 6 && STRNICMP( cookie , == , "Cookie" , cookie_len ) )
		{
			cookie = SOCGIGetHttpHeaderValuePtr( p_header , & cookie_len ) ;
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIGetHttpHeaderValuePtr 'Cookie' data[%.*s]" , cookie_len,cookie )
			
			p = cookie ;
			for( ; ; )
			{
				for( key = p , key_len = 0 ; cookie_len > 0 ; p++ , key_len++ , cookie_len-- )
				{
					if( (*key) == ' ' && key == p )
						key++,key_len--;
					if( (*p) == '=' )
						break;
				}
				if( cookie_len == 0 )
				{
					UnreferObject( rt , out1 );
					return ZLANG_ERROR_INVOKE_METHOD_RETURN;
				}
				
				p++; cookie_len--;
				
				for( value = p , value_len = 0 ; cookie_len > 0 ; p++ , value_len++ , cookie_len-- )
				{
					if( (*value) == ' ' && value == p )
						value++,value_len--;
					if( (*p) == ';' )
						break;
				}
				
				key_obj = CloneStringObject( rt , NULL ) ;
				if( key_obj == NULL )
				{
					UnreferObject( rt , out1 );
					return ZLANG_ERROR_ALLOC;
				}
				CallRuntimeFunction_string_SetStringValue( rt , key_obj , key , key_len );
				EscapeFold( rt , key_obj );
				
				value_obj = CloneStringObject( rt , NULL ) ;
				if( value_obj == NULL )
				{
					UnreferObject( rt , out1 );
					return ZLANG_ERROR_ALLOC;
				}
				CallRuntimeFunction_string_SetStringValue( rt , value_obj , value , value_len );
				EscapeFold( rt , value_obj );
				
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CallRuntimeFunction_map_Put cookie item[%.*s][%.*s]" , key_len,key , value_len,value )
				nret = CallRuntimeFunction_map_Put( rt , out1 , key_obj , value_obj , NULL ) ;
				if( nret )
				{
					UnreferObject( rt , out1 );
					return ZLANG_ERROR_ALLOC;
				}
				
				if( cookie_len == 0 )
					break;
				
				p++; cookie_len--;
			}
		}
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_SetHttpResponse_string;
int ZlangInvokeFunction_SetHttpResponse_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*http_response = NULL ;
	int32_t					http_response_len ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & http_response , NULL );
	
	http_response_len = strlen( http_response ) ;
	if( GetHttpBufferLength(httpserver_direct_prop->http_rsp_headers_buf) == 0 )
		nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , http_response , http_response_len , NULL ) ;
	else
		nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , http_response , http_response_len , GetHttpBufferBase(httpserver_direct_prop->http_rsp_headers_buf,NULL) ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_SetHttpResponseFromFile_string;
int ZlangInvokeFunction_SetHttpResponseFromFile_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*filename = NULL ;
	char					pathfilename[ 4096 ] ;
	char					*filecontent = NULL ;
	int					filecontent_len ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & filename , NULL );
	
	memset( pathfilename , 0x00 , sizeof(pathfilename) );
	snprintf( pathfilename , sizeof(pathfilename)-1 , "%s/%s" , SOCGIGetWwwroot(httpserver_direct_prop->ctx) , filename );
	filecontent = StrdupEntireFile( pathfilename , & filecontent_len ) ;
	if( filecontent == NULL )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	if( GetHttpBufferLength(httpserver_direct_prop->http_rsp_headers_buf) == 0 )
		nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , filecontent , filecontent_len , NULL ) ;
	else
		nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , filecontent , filecontent_len , GetHttpBufferBase(httpserver_direct_prop->http_rsp_headers_buf,NULL) ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIFormatHttpResponse return[%d]" , nret )
	ZLFREE( filecontent );
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	else
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
		return 0;
	}
}

static int SetHttpResponseFromHtmlTemplate_string_htmlsection( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangDirectProperty_httpserver *httpserver_direct_prop , char *html_tpl_pathfilename , struct ZlangDirectProperty_htmlsection *htmlsection_direct_prop )
{
	struct HtmlTemplate			t_html_tpl , *p_html_tpl = NULL ;
	struct HtmlTemplate			*html_tpl = NULL ;
	char					*html = NULL ;
	
	int					nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "html tpl pathfilename[%s]" , html_tpl_pathfilename )
	
	memset( & t_html_tpl , 0x00 , sizeof(struct HtmlTemplate) );
	t_html_tpl.pathfilename = html_tpl_pathfilename ;
	
	html_tpl = QueryHtmlTemplateInTreeByPathfilename( httpserver_direct_prop , & t_html_tpl ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryHtmlTemplateInTreeByPathfilename[%s] return html_tpl[%p]" , t_html_tpl.pathfilename , html_tpl )
	if( html_tpl == NULL )
	{
		html_tpl = p_html_tpl = (struct HtmlTemplate *)ZLMALLOC( sizeof(struct HtmlTemplate) ) ;
		if( html_tpl == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for HtmlTemplate" )
			return ZLANG_ERROR_ALLOC;
		}
		memset( html_tpl , 0x00 , sizeof(struct HtmlTemplate) );
		
		html_tpl->pathfilename = ZLSTRDUP( t_html_tpl.pathfilename ) ;
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ZLSTRDUP to pathfilename[%p][%s]" , html_tpl->pathfilename , html_tpl->pathfilename )
		if( html_tpl->pathfilename == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for HtmlTemplate.pathfilename" )
			return ZLANG_ERROR_ALLOC;
		}
		
		html_tpl->tpl = FTCreateTemplate( html_tpl->pathfilename ) ;
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "FTCreateTemplate[%s] return tpl[%p]" , html_tpl->pathfilename , html_tpl->tpl )
		if( html_tpl->tpl == NULL )
		{
			FreeHtmlTemplate( html_tpl );
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_INVOKE_METHOD_RETURN , "call FTCreateTemplate failed[%d]" , FTGetLastErrorLine() )
			return ZLANG_ERROR_INVOKE_METHOD_RETURN;
		}
	}
	
	html = FTInstantiateTemplate( html_tpl->tpl , GetHtmlSection(htmlsection_direct_prop) ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "FTInstantiateTemplate return html[%s]" , html )
	if( html == NULL )
	{
		FTDestroyTemplate( html_tpl->tpl );
		return 1;
	}
	
	if( GetRuntimeCharsetString(rt) == NULL )
	{
		nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf , HTTP_HEADER_CONTENT_TYPE ": text/html" HTTP_RETURN_NEWLINE ) ;
		if( nret )
		{
			FTDestroyTemplate( html_tpl->tpl );
			return 2;
		}
	}
	else
	{
		nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf , HTTP_HEADER_CONTENT_TYPE ": text/html; charset=%s" HTTP_RETURN_NEWLINE , GetRuntimeCharsetString(rt) ) ;
		if( nret )
		{
			FTDestroyTemplate( html_tpl->tpl );
			return 2;
		}
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIFormatHttpResponse ..." )
	nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , html , strlen(html) , "%s" , GetHttpBufferBase(httpserver_direct_prop->http_rsp_headers_buf,NULL) ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIFormatHttpResponse return[%d]" , nret )
	if( nret )
	{
		FTDestroyTemplate( html_tpl->tpl );
		return 2;
	}
	
	if( p_html_tpl )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "LinkHtmlTemplateToTreeByPathfilename html_tpl[%p]" , html_tpl )
		LinkHtmlTemplateToTreeByPathfilename( httpserver_direct_prop , html_tpl );
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_SetHttpResponseFromHtmlTemplate_string_htmlsection;
int ZlangInvokeFunction_SetHttpResponseFromHtmlTemplate_string_htmlsection( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangDirectProperty_htmlsection	*htmlsection_direct_prop = GetObjectDirectProperty(in2) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*html_tpl_filename = NULL ;
	char					html_tpl_pathfilename[ 4096 ] ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & html_tpl_filename , NULL );
	
	memset( html_tpl_pathfilename , 0x00 , sizeof(html_tpl_pathfilename) );
	snprintf( html_tpl_pathfilename , sizeof(html_tpl_pathfilename)-1 , "%s/%s" , SOCGIGetWwwroot(httpserver_direct_prop->ctx) , html_tpl_filename );
	nret = SetHttpResponseFromHtmlTemplate_string_htmlsection( rt , obj , httpserver_direct_prop , html_tpl_pathfilename , htmlsection_direct_prop ) ;
	if( nret < 0 )
	{
		return nret;
	}
	else if( nret > 0 )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	else
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
		return 0;
	}
}

ZlangInvokeFunction ZlangInvokeFunction_FormatHttpResponse_vargs;
int ZlangInvokeFunction_FormatHttpResponse_vargs( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	struct ZlangObject			*buf_obj = NULL ;
	char					*str = NULL ;
	int32_t					str_len ;
	
	int					nret = 0 ;
	
	buf_obj = CloneStringObjectInTmpStack( rt , NULL ) ;
	if( buf_obj == NULL )
		return GetRuntimeErrorNo(rt);
	
	nret = CallRuntimeFunction_string_AppendFormatFromArgsStack( rt , buf_obj ) ;
	if( nret )
		return nret;
	
	GetDataPtr( rt , buf_obj , (void**) & str , & str_len );
	
	nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , str , str_len , NULL ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_WriteHttpResponseHeader_string_string;
int ZlangInvokeFunction_WriteHttpResponseHeader_string_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*name = NULL ;
	char					*value = NULL ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & name , NULL );
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & value , NULL );
	
	nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf , "%s: %s" HTTP_RETURN_NEWLINE , name , value ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_WriteHttpResponseCookie_string_string_int;
int ZlangInvokeFunction_WriteHttpResponseCookie_string_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	struct ZlangObject			*in3 = GetInputParameterInLocalObjectStack(rt,3) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*name = NULL ;
	char					*value = NULL ;
	int32_t					max_age ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & name , NULL );
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & value , NULL );
	CallRuntimeFunction_int_GetIntValue( rt , in3 , & max_age );
	
	if( max_age == 0 )
		nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf , "Set-Cookie: %s=%s; expires=Thu, Jan 01 1970 00:00:00 UTC" HTTP_RETURN_NEWLINE , name , value ) ;
	else
		nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf , "Set-Cookie: %s=%s;maxAge=%d" HTTP_RETURN_NEWLINE , name , value , max_age ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_WriteHttpResponseBody_string;
int ZlangInvokeFunction_WriteHttpResponseBody_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*body = NULL ;
	
	int					nret = 0 ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & body , NULL );
	
	nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_body_buf , "%s" , body ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_FormatWriteHttpResponseBody_vargs;
int ZlangInvokeFunction_FormatWriteHttpResponseBody_vargs( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	struct ZlangObject			*buf_obj = NULL ;
	char					*str = NULL ;
	int32_t					str_len ;
	
	int					nret = 0 ;
	
	buf_obj = CloneStringObjectInTmpStack( rt , NULL ) ;
	if( buf_obj == NULL )
		return GetRuntimeErrorNo(rt);
	
	nret = CallRuntimeFunction_string_AppendFormatFromArgsStack( rt , buf_obj ) ;
	if( nret )
		return nret;
	
	GetDataPtr( rt , buf_obj , (void**) & str , & str_len );
	
	nret = StrcatfHttpBuffer( httpserver_direct_prop->http_rsp_body_buf , "%.*s" , str_len,str ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_WriteHttpResponseEnd;
int ZlangInvokeFunction_WriteHttpResponseEnd( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	char					*http_rsp_headers = NULL ;
	int					http_rsp_headers_len ;
	char					*http_rsp_body = NULL ;
	int					http_rsp_body_len ;
	
	int					nret = 0 ;
	
	http_rsp_headers = GetHttpBufferBase( httpserver_direct_prop->http_rsp_headers_buf , & http_rsp_headers_len ) ;
	http_rsp_body = GetHttpBufferBase( httpserver_direct_prop->http_rsp_body_buf , & http_rsp_body_len ) ;
	nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , http_rsp_body , http_rsp_body_len , "%.*s" , http_rsp_headers_len,http_rsp_headers ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

static int AddMatchingUriFunctionCache( struct ZlangRuntime *rt , struct ZlangFunction *func , char *func_name , int func_name_len , struct list_head *list )
{
	char				*p1 = NULL ;
	char				*p2 = NULL ;
	struct MatchingUriFunctionCache	*matching_uri_func_cache = NULL ;
	int				dir_array_index ;
	int				dir_array_size = sizeof(((struct MatchingUriFunctionCache *)0)->dir_array)/sizeof(((struct MatchingUriFunctionCache *)0)->dir_array[0]) ;
	char				*uri_over_end = func_name + func_name_len ;
	
	matching_uri_func_cache = (struct MatchingUriFunctionCache *)ZLMALLOC( sizeof(struct MatchingUriFunctionCache) ) ;
	if( matching_uri_func_cache == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "alloc failed , errno[%d]" , errno )
		return -1;
	}
	memset( matching_uri_func_cache , 0x00 , sizeof(struct MatchingUriFunctionCache) );
	
	p1 = func_name ;
	for( dir_array_index = 0 ; dir_array_index < dir_array_size ; dir_array_index++ )
	{
		p2 = strchr( p1+1 , '/' ) ;
		if( p2 == NULL )
			p2 = uri_over_end ;
		
		matching_uri_func_cache->dir_array[dir_array_index].dir_name = p1 + 1 ;
		matching_uri_func_cache->dir_array[dir_array_index].dir_name_len = p2 - (p1+1) ;
		
		if( p2 == uri_over_end )
			break;
		p1 = p2 ;
	}
	if( dir_array_index >= dir_array_size )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func_name[%.*s] dir array overflow" , func_name_len,func_name )
		return -2;
	}
	
	matching_uri_func_cache->dir_count = dir_array_index + 1 ;
	matching_uri_func_cache->func = func ;
	
	list_add_tail( & (matching_uri_func_cache->matching_uri_func_cache_list_node) , list );
	
	return 0;
}

static int InitAllMatchingUriFunctionCaches( struct ZlangRuntime *rt , struct ZlangDirectProperty_httpserver *httpserver_direct_prop )
{
	struct ZlangFunction	*func = NULL ;
	char			*func_name = NULL ;
	int			func_name_len ;
	int			nret = 0 ;
	
	for( ; ; )
	{
		func = TravelGlobalFunctionByFullFunctionName( rt , func ) ;
		if( func == NULL )
			break;
		
		func_name = GetFunctionName( func ) ;
		func_name_len = strlen(func_name) ;
		if( func_name_len > sizeof("GET ")-1 && MEMCMP( func_name , == , "GET " , sizeof("GET ")-1 ) && func_name[sizeof("GET ")-1] == '/' )
		{
			nret = AddMatchingUriFunctionCache( rt , func , func_name+(sizeof("GET ")-1) , func_name_len-(sizeof("GET ")-1) , & (httpserver_direct_prop->get_matching_uri_func_cache_list) ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to GET cache failed[%d]" , func_name+(sizeof("GET ")-1) , nret )
				return -1;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to GET cache ok" , func_name+(sizeof("GET ")-1) )
			}
		}
		else if( func_name_len > sizeof("POST ")-1 && MEMCMP( func_name , == , "POST " , sizeof("POST ")-1 ) && func_name[sizeof("POST ")-1] == '/' )
		{
			nret = AddMatchingUriFunctionCache( rt , func , func_name+(sizeof("POST ")-1) , func_name_len-(sizeof("POST ")-1) , & (httpserver_direct_prop->post_matching_uri_func_cache_list) ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to POST cache failed[%d]" , func_name+(sizeof("POST ")-1) , nret )
				return -1;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to POST cache ok" , func_name+(sizeof("POST ")-1) )
			}
		}
		else if( func_name_len > sizeof("PUT ")-1 && MEMCMP( func_name , == , "PUT " , sizeof("PUT ")-1 ) && func_name[sizeof("PUT ")-1] == '/' )
		{
			nret = AddMatchingUriFunctionCache( rt , func , func_name+(sizeof("PUT ")-1) , func_name_len-(sizeof("PUT ")-1) , & (httpserver_direct_prop->put_matching_uri_func_cache_list) ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to PUT cache failed[%d]" , func_name+(sizeof("PUT ")-1) , nret )
				return -1;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to PUT cache ok" , func_name+(sizeof("PUT ")-1) )
			}
		}
		else if( func_name_len > sizeof("PATCH ")-1 && MEMCMP( func_name , == , "PATCH " , sizeof("PATCH ")-1 ) && func_name[sizeof("PATCH ")-1] == '/' )
		{
			nret = AddMatchingUriFunctionCache( rt , func , func_name+(sizeof("PATCH ")-1) , func_name_len-(sizeof("PATCH ")-1) , & (httpserver_direct_prop->patch_matching_uri_func_cache_list) ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to PATCH cache failed[%d]" , func_name+(sizeof("PATCH ")-1) , nret )
				return -1;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to PATCH cache ok" , func_name+(sizeof("PATCH ")-1) )
			}
		}
		else if( func_name_len > sizeof("DELETE ")-1 && MEMCMP( func_name , == , "DELETE " , sizeof("DELETE ")-1 ) && func_name[sizeof("DELETE ")-1] == '/' )
		{
			nret = AddMatchingUriFunctionCache( rt , func , func_name+(sizeof("DELETE ")-1) , func_name_len-(sizeof("DELETE ")-1) , & (httpserver_direct_prop->delete_matching_uri_func_cache_list) ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to DELETE cache failed[%d]" , func_name+(sizeof("DELETE ")-1) , nret )
				return -1;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "AddMatchingUriFunctionCache \"%s\" to DELETE cache ok" , func_name+(sizeof("DELETE ")-1) )
			}
		}
	}
	
	return 0;
}

static struct ZlangFunction *QueryMatchingUriFunctionCache( struct ZlangRuntime *rt , char *uri , int uri_len , struct list_head *list )
{
	struct MatchingUriFunctionCache	*matching_uri_func_cache = NULL ;
	char				*p1 = NULL ;
	int				len1 ;
	char				*p2 = NULL ;
	int				dir_array_index ;
	char				*uri_over_end = uri + uri_len ;
	
	list_for_each_entry( matching_uri_func_cache , list , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		p1 = uri + 1 ;
		for( dir_array_index = 0 ; dir_array_index < matching_uri_func_cache->dir_count ; dir_array_index++ )
		{
			p2 = memchr( p1 , '/' , uri_len-(p1-uri) ) ;
			if( p2 == NULL )
			{
				p2 = uri_over_end ;
			}
			len1 = p2 - p1 ;
			
			if( matching_uri_func_cache->dir_array[dir_array_index].dir_name_len == 1 && matching_uri_func_cache->dir_array[dir_array_index].dir_name[0] == '*' )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "matched cache[%.*s] uri[%.*s]" , matching_uri_func_cache->dir_array[dir_array_index].dir_name_len,matching_uri_func_cache->dir_array[dir_array_index].dir_name , len1,p1 )
			}
			else if( matching_uri_func_cache->dir_array[dir_array_index].dir_name_len == p2 - p1 && MEMCMP( matching_uri_func_cache->dir_array[dir_array_index].dir_name , == , p1 , matching_uri_func_cache->dir_array[dir_array_index].dir_name_len ) )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "matched cache[%.*s] uri[%.*s]" , matching_uri_func_cache->dir_array[dir_array_index].dir_name_len,matching_uri_func_cache->dir_array[dir_array_index].dir_name , len1,p1 )
			}
			else if( matching_uri_func_cache->dir_array[dir_array_index].dir_name_len == 2 && matching_uri_func_cache->dir_array[dir_array_index].dir_name[0] == '*' && matching_uri_func_cache->dir_array[dir_array_index].dir_name[1] == '*' )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "matched cache[%.*s] uri[%.*s]" , matching_uri_func_cache->dir_array[dir_array_index].dir_name_len,matching_uri_func_cache->dir_array[dir_array_index].dir_name , len1,p1 )
				return matching_uri_func_cache->func;
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "unmatched cache[%.*s] uri[%.*s]" , matching_uri_func_cache->dir_array[dir_array_index].dir_name_len,matching_uri_func_cache->dir_array[dir_array_index].dir_name , len1,p1 )
				break;
			}
			
			p1 = p2 + 1 ;
		}
		if( dir_array_index >= matching_uri_func_cache->dir_count && p1 == uri_over_end + 1 )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "all dir matched" )
			return matching_uri_func_cache->func;
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "dir unmatched , try next cache" )
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "all cache unmatched" )
	
	return NULL;
}

static struct ZlangFunction *QueryMatchingUriFunctionCaches( struct ZlangRuntime *rt , struct ZlangDirectProperty_httpserver *httpserver_direct_prop , char *method , int method_len , char *uri , int uri_len )
{
	struct ZlangFunction	*func = NULL ;
	
	if( method_len == sizeof("GET")-1 && MEMCMP( method , == , "GET" , method_len ) )
	{
		func = QueryMatchingUriFunctionCache( rt , uri , uri_len , & (httpserver_direct_prop->get_matching_uri_func_cache_list) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from GET cache failed" , uri_len,uri )
			return NULL;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from GET cache ok , func[%s][%s]" , uri_len,uri , GetFunctionName(func) , GetFullFunctionName(func) )
			return func;
		}
	}
	else if( method_len == sizeof("POST")-1 && MEMCMP( method , == , "POST" , method_len ) )
	{
		func = QueryMatchingUriFunctionCache( rt , uri , uri_len , & (httpserver_direct_prop->post_matching_uri_func_cache_list) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from POST cache failed" , uri_len,uri )
			return NULL;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from POST cache ok , func[%s][%s]" , uri_len,uri , GetFunctionName(func) , GetFullFunctionName(func) )
			return func;
		}
	}
	else if( method_len == sizeof("PUT")-1 && MEMCMP( method , == , "PUT" , method_len ) )
	{
		func = QueryMatchingUriFunctionCache( rt , uri , uri_len , & (httpserver_direct_prop->put_matching_uri_func_cache_list) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from PUT cache failed" , uri_len,uri )
			return NULL;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from PUT cache ok , func[%s][%s]" , uri_len,uri , GetFunctionName(func) , GetFullFunctionName(func) )
			return func;
		}
	}
	else if( method_len == sizeof("PATCH")-1 && MEMCMP( method , == , "PATCH" , method_len ) )
	{
		func = QueryMatchingUriFunctionCache( rt , uri , uri_len , & (httpserver_direct_prop->patch_matching_uri_func_cache_list) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from PUT cache failed" , uri_len,uri )
			return NULL;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from PUT cache ok , func[%s][%s]" , uri_len,uri , GetFunctionName(func) , GetFullFunctionName(func) )
			return func;
		}
	}
	else if( method_len == sizeof("DELETE")-1 && MEMCMP( method , == , "DELETE" , method_len ) )
	{
		func = QueryMatchingUriFunctionCache( rt , uri , uri_len , & (httpserver_direct_prop->delete_matching_uri_func_cache_list) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from DELETE cache failed" , uri_len,uri )
			return NULL;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from DELETE cache ok , func[%s][%s]" , uri_len,uri , GetFunctionName(func) , GetFullFunctionName(func) )
			return func;
		}
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryMatchingUriFunctionCache [%.*s] from %.*s not support" , uri_len,uri , method_len,method )
		return NULL;
	}
}

funcCallHttpApplication CallHttpApplication;
int CallHttpApplication( struct HttpApplicationContext *ctx )
{
#if 0
	int		nret = 0 ;
	
	nret = SOCGIFormatHttpResponse( ctx , "hello" , 5 , NULL ) ;
	if( nret )
	{
		return HTTP_INTERNAL_SERVER_ERROR;
	}
#endif
	struct ZlangRuntime			*rt = SOCGIGetUserData(ctx) ;
	
	struct ZlangObject			*httpserver_obj = GetRuntimeInObject(rt) ;
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(httpserver_obj) ;
	
	char					*method = NULL ;
	int					method_len ;
	char					*uri = NULL ;
	int					uri_len ;
	char					*p3 = NULL ;
	struct ZlangFunction			*func = NULL ;
	struct ZlangFunctionParameter		*in_param = NULL ;
	struct ZlangFunctionParameter		*out_param = NULL ;
	
	struct ZlangObject			*obj = NULL ;
	struct ZlangObjectsStackInfo		*new_local_objs_stack_info = NULL ;
	
	char					err_info[ 1024 ] ;
	
	struct ZlangObject			*return_obj = NULL ;
	int					return_value ;
	
	int					nret = 0 ;
	
	httpserver_direct_prop->ctx = ctx ;
	
	method = SOCGIGetHttpHeaderPtr_METHOD( ctx , & method_len ) ;
	uri = SOCGIGetHttpHeaderPtr_URI( ctx , & uri_len ) ;
	if( uri[0] != '/' )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "uri[%.*s] not begin with '/'" , uri_len,uri )
		return HTTP_BAD_REQUEST;
	}
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "http uri[%.*s]" , uri_len,uri )
	
	p3 = memchr( uri , '?' , uri_len ) ;
	if( p3 )
	{
		uri_len = p3 - uri ;
	}
	
	if( httpserver_direct_prop->init_matching_uri_func_cache_flag == 0 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InitAllMatchingUriFunctionCaches ..." )
		nret = InitAllMatchingUriFunctionCaches( rt , httpserver_direct_prop ) ;
		if( nret )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InitAllMatchingUriFunctionCaches failed[%d]" , nret )
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InitAllMatchingUriFunctionCaches ok" )
		}
		
		httpserver_direct_prop->init_matching_uri_func_cache_flag = 1 ;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "query func by uri[%.*s]" , uri_len,uri )
	func = QueryMatchingUriFunctionCaches( rt , httpserver_direct_prop , method , method_len , uri , uri_len ) ;
	if( func == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func not found by uri[%.*s]" , uri_len,uri )
		return HTTP_NOT_IMPLEMENTED;
	} 
	
	IncreaseStackInfo( rt , GetFullFunctionName(func) );
	new_local_objs_stack_info = GetCurrentLocalObjectsStackInfo( rt ) ;
	/*
	new_tmp_objs_stack_info = GetCurrentTmpObjectsStackInfo( rt ) ;
	new_defers_stack_info = GetCurrentDefersStackInfo( rt ) ;
	*/
	
	in_param = TravelFunctionInputParameter( rt , func , NULL ) ;
	if( in_param == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func[%s] no in param" , GetFunctionName(func) )
		return HTTP_NOT_IMPLEMENTED;
	}
	if( STRCMP( GetFunctionParameterParentObjectName(in_param) , != , "httpserver" ) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func[%s] in param type[%s] invalid" , GetFunctionName(func) , GetFunctionParameterParentObjectName(in_param) )
		return HTTP_NOT_IMPLEMENTED;
	}
	if( TravelFunctionInputParameter( rt , func , in_param ) != NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func[%s] has more in params" , GetFunctionName(func) )
		return HTTP_NOT_IMPLEMENTED;
	}
	
	out_param = GetFunctionOutParameter( func ) ;
	if( out_param == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func[%s] no out param" , GetFunctionName(func) )
		return HTTP_NOT_IMPLEMENTED;
	}
	if( STRCMP( GetFunctionParameterParentObjectName(out_param) , != , "int" ) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "func[%s] out param type[%s] invalid" , GetFunctionName(func) , GetFunctionParameterParentObjectName(out_param) )
		return HTTP_NOT_IMPLEMENTED;
	}
	
	obj = ReferObjectInLocalStack( rt , GetFunctionParameterObjectName(in_param) , httpserver_obj ) ;
	if( obj == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ReferObjectInLocalStack in param failed[%d]" , nret )
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "ReferObjectInLocalStack in param ok , " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
	}
	
	MarkInputParamtersTop( new_local_objs_stack_info );
	
	return_obj = CloneIntObjectInLocalStack( rt , NULL ) ;
	if( return_obj == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneIntObject failed" )
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "CloneIntObject ok , " ); DebugPrintObject( rt , return_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
	}
	
	MarkOutputParamtersTop( new_local_objs_stack_info );
	
	/*
	SetObjectsStackFullFuncName( new_local_objs_stack_info , GetFullFunctionName(func) );
	SetObjectsStackFullFuncName( new_tmp_objs_stack_info , GetFullFunctionName(func) );
	SetDefersStackFullFuncName( new_defers_stack_info , GetFullFunctionName(func) );
	*/
	
	ResetHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf );
	ResetHttpBuffer( httpserver_direct_prop->http_rsp_body_buf );
	
	nret = SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , NULL , -1 , NULL ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIFormatHttpResponse failed[%d]" , nret );
		return HTTP_INTERNAL_SERVER_ERROR;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "SOCGIFormatHttpResponse ok" );
	}
	
	nret = InvokeEntryFunction( rt , NULL , func ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InvokeEntryFunction failed[%d]" , nret )
		memset( err_info , 0x00 , sizeof(err_info) );
		FillRuntimeErrorString( rt , err_info , sizeof(err_info) );
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "%s" , err_info )
		SOCGIFormatHttpResponse( httpserver_direct_prop->ctx , err_info , strlen(err_info) , NULL );
		/*
		DestroyObject( rt , return_obj );
		*/
		DecreaseStackInfo( rt );
		return HTTP_OK;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InvokeEntryFunction ok" )
	}
	
	CallRuntimeFunction_int_GetIntValue( rt , return_obj , & return_value );
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "return_value[%d]" , return_value )
	/*
	DestroyObject( rt , return_obj );
	*/
	DecreaseStackInfo( rt );
	
	return return_value;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetListenAddress_string_int;
int ZlangInvokeFunction_httpserver_SetListenAddress_string_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	char					*ip = NULL ;
	int32_t					port ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & ip , NULL );
	CallRuntimeFunction_int_GetIntValue( rt , in2 , & port );
	
	snprintf( httpserver_direct_prop->ip , sizeof(httpserver_direct_prop->ip)-1 , "%s" , ip );
	httpserver_direct_prop->port = port ;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetDomain_string;
int ZlangInvokeFunction_httpserver_SetDomain_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	char					*domain = NULL ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & domain , NULL );
	
	snprintf( httpserver_direct_prop->domain , sizeof(httpserver_direct_prop->domain)-1 , "%s" , domain );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetWwwroot_string;
int ZlangInvokeFunction_httpserver_SetWwwroot_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	char					*wwwroot = NULL ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & wwwroot , NULL );
	
	snprintf( httpserver_direct_prop->wwwroot , sizeof(httpserver_direct_prop->wwwroot)-1 , "%s" , wwwroot );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetIndex_string;
int ZlangInvokeFunction_httpserver_SetIndex_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	char					*index = NULL ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & index , NULL );
	
	snprintf( httpserver_direct_prop->index , sizeof(httpserver_direct_prop->index)-1 , "%s" , index );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetSocgiType_string;
int ZlangInvokeFunction_httpserver_SetSocgiType_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	char					*socgi_type = NULL ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & socgi_type , NULL );
	
	snprintf( httpserver_direct_prop->socgi_type , sizeof(httpserver_direct_prop->socgi_type)-1 , "%s" , socgi_type );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetLogFile_string_string;
int ZlangInvokeFunction_httpserver_SetLogFile_string_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*in2 = GetInputParameterInLocalObjectStack(rt,2) ;
	char					*access_log = NULL ;
	char					*error_log = NULL ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & access_log , NULL );
	CallRuntimeFunction_string_GetStringValue( rt , in2 , & error_log , NULL );
	
	snprintf( httpserver_direct_prop->access_log , sizeof(httpserver_direct_prop->access_log)-1 , "%s" , access_log );
	snprintf( httpserver_direct_prop->error_log , sizeof(httpserver_direct_prop->error_log)-1 , "%s" , error_log );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_DisableXForwardedFor_bool;
int ZlangInvokeFunction_httpserver_DisableXForwardedFor_bool( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	unsigned char				disable_x_forwarded_for ;
	
	CallRuntimeFunction_bool_GetBoolValue( rt , in1 , & disable_x_forwarded_for );
	
	httpserver_direct_prop->disable_x_forwarded_for = disable_x_forwarded_for ;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_SetWorkerProcesses_int;
int ZlangInvokeFunction_httpserver_SetWorkerProcesses_int( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	int32_t					worker_processes ;
	
	CallRuntimeFunction_int_GetIntValue( rt , in1 , & worker_processes );
	
	httpserver_direct_prop->worker_processes = worker_processes ;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_httpserver_Run;
int ZlangInvokeFunction_httpserver_Run( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	hetao_conf				*conf = NULL ;
	int					nret = 0 ;
	
	conf = (hetao_conf *)ZLMALLOC( sizeof(hetao_conf) ) ;
	if( conf == NULL )
	{
		CallRuntimeFunction_int_SetIntValue( rt , out1 , ZLANG_FATAL_INVOKE_METHOD_RETURN );
		return ZLANG_FATAL_INVOKE_METHOD_RETURN;
	}
	memset( conf , 0x00 , sizeof(hetao_conf) );
	
	conf->worker_processes = httpserver_direct_prop->worker_processes ;
	
	strcpy( conf->listen[0].ip , httpserver_direct_prop->ip );
	conf->listen[0].port = httpserver_direct_prop->port ;
	conf->_listen_count = 1 ;
	
	snprintf( conf->listen[0].website[0].domain , sizeof(conf->listen[0].website[0].domain) , "%s" , httpserver_direct_prop->domain );
	snprintf( conf->listen[0].website[0].wwwroot , sizeof(conf->listen[0].website[0].wwwroot) , "%s" , httpserver_direct_prop->wwwroot );
	snprintf( conf->listen[0].website[0].index , sizeof(conf->listen[0].website[0].index) , "%s" , httpserver_direct_prop->index );
	snprintf( conf->listen[0].website[0].socgi.socgi_type , sizeof(conf->listen[0].website[0].socgi.socgi_type) , "%s" , httpserver_direct_prop->socgi_type );
	
	if( httpserver_direct_prop->access_log[0] == '/' )
		snprintf( conf->listen[0].website[0].access_log , sizeof(conf->listen[0].website[0].access_log) , "%s" , httpserver_direct_prop->access_log );
	else
		snprintf( conf->listen[0].website[0].access_log , sizeof(conf->listen[0].website[0].access_log) , "%s/%s" , getenv("HOME") , httpserver_direct_prop->access_log );
	if( httpserver_direct_prop->error_log[0] == '/' )
		snprintf( conf->error_log , sizeof(conf->error_log) , "%s" , httpserver_direct_prop->error_log );
	else
		snprintf( conf->error_log , sizeof(conf->error_log) , "%s/%s" , getenv("HOME") , httpserver_direct_prop->error_log );
	snprintf( conf->log_level , sizeof(conf->log_level) , "%s" , GetRuntimeDebugErrorLevelStringPtr(rt) );
	conf->listen[0].website[0].disable_x_forwarded_for = httpserver_direct_prop->disable_x_forwarded_for ;
	
	nret = RunHttpServer( conf , & CallHttpApplication , rt ) ;
	if( nret )
	{
		ZLFREE( conf );
		CallRuntimeFunction_int_SetIntValue( rt , out1 , nret );
		return 0;
	}
	
	ZLFREE( conf );
	CallRuntimeFunction_int_SetIntValue( rt , out1 , 0 );
	return 0;
}

ZlangCreateDirectPropertyFunction ZlangCreateDirectProperty_httpserver;
void *ZlangCreateDirectProperty_httpserver( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = NULL ;
	
	httpserver_direct_prop = (struct ZlangDirectProperty_httpserver *)ZLMALLOC( sizeof(struct ZlangDirectProperty_httpserver) ) ;
	if( httpserver_direct_prop == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for entity" )
		return NULL;
	}
	memset( httpserver_direct_prop , 0x00 , sizeof(struct ZlangDirectProperty_httpserver) );
	
	httpserver_direct_prop->http_rsp_headers_buf = AllocHttpBuffer( 1024 ) ;
	if( httpserver_direct_prop->http_rsp_headers_buf == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for http response headers" )
		return NULL;
	}
	
	httpserver_direct_prop->http_rsp_body_buf = AllocHttpBuffer( 4096 ) ;
	if( httpserver_direct_prop->http_rsp_body_buf == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for http response body" )
		return NULL;
	}
	
	httpserver_direct_prop->init_matching_uri_func_cache_flag = 0 ;
	INIT_LIST_HEAD( & (httpserver_direct_prop->get_matching_uri_func_cache_list) );
	INIT_LIST_HEAD( & (httpserver_direct_prop->post_matching_uri_func_cache_list) );
	INIT_LIST_HEAD( & (httpserver_direct_prop->put_matching_uri_func_cache_list) );
	INIT_LIST_HEAD( & (httpserver_direct_prop->patch_matching_uri_func_cache_list) );
	INIT_LIST_HEAD( & (httpserver_direct_prop->delete_matching_uri_func_cache_list) );
	
	return httpserver_direct_prop;
}

ZlangDestroyDirectPropertyFunction ZlangDestroyDirectProperty_httpserver;
void ZlangDestroyDirectProperty_httpserver( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct MatchingUriFunctionCache		*matching_uri_func_cache = NULL ;
	struct MatchingUriFunctionCache		*next_matching_uri_func_cache = NULL ;
	
	FreeHttpBuffer( httpserver_direct_prop->http_rsp_headers_buf );
	FreeHttpBuffer( httpserver_direct_prop->http_rsp_body_buf );
	
	list_for_each_entry_safe( matching_uri_func_cache , next_matching_uri_func_cache , & (httpserver_direct_prop->get_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		list_del( & (matching_uri_func_cache->matching_uri_func_cache_list_node) );
		ZLFREE( matching_uri_func_cache );
	}
	
	list_for_each_entry_safe( matching_uri_func_cache , next_matching_uri_func_cache , & (httpserver_direct_prop->post_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		list_del( & (matching_uri_func_cache->matching_uri_func_cache_list_node) );
		ZLFREE( matching_uri_func_cache );
	}
	
	list_for_each_entry_safe( matching_uri_func_cache , next_matching_uri_func_cache , & (httpserver_direct_prop->put_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		list_del( & (matching_uri_func_cache->matching_uri_func_cache_list_node) );
		ZLFREE( matching_uri_func_cache );
	}
	
	list_for_each_entry_safe( matching_uri_func_cache , next_matching_uri_func_cache , & (httpserver_direct_prop->patch_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		list_del( & (matching_uri_func_cache->matching_uri_func_cache_list_node) );
		ZLFREE( matching_uri_func_cache );
	}
	
	list_for_each_entry_safe( matching_uri_func_cache , next_matching_uri_func_cache , & (httpserver_direct_prop->delete_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		list_del( & (matching_uri_func_cache->matching_uri_func_cache_list_node) );
		ZLFREE( matching_uri_func_cache );
	}
	
	DestroyHtmlTemplateTree( httpserver_direct_prop );
	
	ZLFREE( httpserver_direct_prop );
	
	return;
}

ZlangSummarizeDirectPropertySizeFunction ZlangSummarizeDirectPropertySize_httpserver;
void ZlangSummarizeDirectPropertySize_httpserver( struct ZlangRuntime *rt , struct ZlangObject *obj , size_t *summarized_obj_size , size_t *summarized_direct_prop_size )
{
	struct ZlangDirectProperty_httpserver	*httpserver_direct_prop = GetObjectDirectProperty(obj) ;
	struct MatchingUriFunctionCache		*matching_uri_func_cache = NULL ;
	int					i ;
	struct HtmlTemplate			*html_tpl = NULL ;
	
	list_for_each_entry( matching_uri_func_cache , & (httpserver_direct_prop->get_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		for( i = 0 ; i < MAX_DIR_ARRAY ; i++ )
		{
			if( matching_uri_func_cache->dir_array[i].dir_name )
				SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(matching_uri_func_cache->dir_array[i].dir_name)+1 )
		}
		
		if( matching_uri_func_cache->func )
			SummarizeFunctionSize( rt , matching_uri_func_cache->func , summarized_obj_size );
	}
	
	list_for_each_entry( matching_uri_func_cache , & (httpserver_direct_prop->post_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		for( i = 0 ; i < MAX_DIR_ARRAY ; i++ )
		{
			if( matching_uri_func_cache->dir_array[i].dir_name )
				SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(matching_uri_func_cache->dir_array[i].dir_name)+1 )
		}
		
		if( matching_uri_func_cache->func )
			SummarizeFunctionSize( rt , matching_uri_func_cache->func , summarized_obj_size );
	}
	
	list_for_each_entry( matching_uri_func_cache , & (httpserver_direct_prop->put_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		for( i = 0 ; i < MAX_DIR_ARRAY ; i++ )
		{
			if( matching_uri_func_cache->dir_array[i].dir_name )
				SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(matching_uri_func_cache->dir_array[i].dir_name)+1 )
		}
		
		if( matching_uri_func_cache->func )
			SummarizeFunctionSize( rt , matching_uri_func_cache->func , summarized_obj_size );
	}
	
	list_for_each_entry( matching_uri_func_cache , & (httpserver_direct_prop->patch_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		for( i = 0 ; i < MAX_DIR_ARRAY ; i++ )
		{
			if( matching_uri_func_cache->dir_array[i].dir_name )
				SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(matching_uri_func_cache->dir_array[i].dir_name)+1 )
		}
		
		if( matching_uri_func_cache->func )
			SummarizeFunctionSize( rt , matching_uri_func_cache->func , summarized_obj_size );
	}
	
	list_for_each_entry( matching_uri_func_cache , & (httpserver_direct_prop->delete_matching_uri_func_cache_list) , struct MatchingUriFunctionCache , matching_uri_func_cache_list_node )
	{
		for( i = 0 ; i < MAX_DIR_ARRAY ; i++ )
		{
			if( matching_uri_func_cache->dir_array[i].dir_name )
				SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(matching_uri_func_cache->dir_array[i].dir_name)+1 )
		}
		
		if( matching_uri_func_cache->func )
			SummarizeFunctionSize( rt , matching_uri_func_cache->func , summarized_obj_size );
	}
	
	html_tpl = NULL ;
	while( ( html_tpl = TravelHtmlTemplateInTreeByPathfilename(httpserver_direct_prop,html_tpl) ) )
	{
		if( html_tpl->pathfilename )
			SUMMARIZE_SIZE( summarized_direct_prop_size , strlen(html_tpl->pathfilename)+1 )
	}
	
	SUMMARIZE_SIZE( summarized_direct_prop_size , sizeof(struct ZlangDirectProperty_httpserver) )
	
	return;
}

static struct ZlangDirectFunctions direct_funcs_httpserver =
	{
		ZLANG_OBJECT_httpserver , /* char *ancestor_name */
		
		ZlangCreateDirectProperty_httpserver , /* ZlangCreateDirectPropertyFunction *create_entity_func */
		ZlangDestroyDirectProperty_httpserver , /* ZlangDestroyDirectPropertyFunction *destroy_entity_func */
		
		NULL , /* ZlangFromCharPtrFunction *from_char_ptr_func */
		NULL , /* ZlangToStringFunction *to_string_func */
		NULL , /* ZlangFromDataPtrFunction *from_data_ptr_func */
		NULL , /* ZlangGetDataPtrFunction *get_data_ptr_func */
		
		NULL , /* ZlangOperatorFunction *oper_PLUS_func */
		NULL , /* ZlangOperatorFunction *oper_MINUS_func */
		NULL , /* ZlangOperatorFunction *oper_MUL_func */
		NULL , /* ZlangOperatorFunction *oper_DIV_func */
		NULL , /* ZlangOperatorFunction *oper_MOD_func */
		
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NEGATIVE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NOT_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_BIT_REVERSE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_PLUS_PLUS_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_MINUS_MINUS_func */
		
		NULL , /* ZlangCompareFunction *comp_EGUAL_func */
		NULL , /* ZlangCompareFunction *comp_NOTEGUAL_func */
		NULL , /* ZlangCompareFunction *comp_LT_func */
		NULL , /* ZlangCompareFunction *comp_LE_func */
		NULL , /* ZlangCompareFunction *comp_GT_func */
		NULL , /* ZlangCompareFunction *comp_GE_func */
		
		NULL , /* ZlangLogicFunction *logic_AND_func */
		NULL , /* ZlangLogicFunction *logic_OR_func */
		
		NULL , /* ZlangLogicFunction *bit_AND_func */
		NULL , /* ZlangLogicFunction *bit_XOR_func */
		NULL , /* ZlangLogicFunction *bit_OR_func */
		NULL , /* ZlangLogicFunction *bit_MOVELEFT_func */
		NULL , /* ZlangLogicFunction *bit_MOVERIGHT_func */
		
		ZlangSummarizeDirectPropertySize_httpserver , /* ZlangSummarizeDirectPropertySizeFunction *summarize_direct_prop_size_func */
	} ;

ZlangImportObjectFunction ZlangImportObject_httpserver;
struct ZlangObject *ZlangImportObject_httpserver( struct ZlangRuntime *rt )
{
	struct ZlangObject	*obj = NULL ;
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	nret = ImportObject( rt , & obj , ZLANG_OBJECT_httpserver , & direct_funcs_httpserver , sizeof(struct ZlangDirectFunctions) , NULL ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "import object to global objects heap" )
		return NULL;
	}
	
	/* httpserver.SetListenAddress(string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetListenAddress" , "SetListenAddress(string,int)" , ZlangInvokeFunction_httpserver_SetListenAddress_string_int , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetDomain(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetDomain" , "SetDomain(string)" , ZlangInvokeFunction_httpserver_SetDomain_string , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetWwwroot(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetWwwroot" , "SetWwwroot(string)" , ZlangInvokeFunction_httpserver_SetWwwroot_string , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetIndex(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetIndex" , "SetIndex(string)" , ZlangInvokeFunction_httpserver_SetIndex_string , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetSocgiType(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetSocgiType" , "SetSocgiType(string)" , ZlangInvokeFunction_httpserver_SetSocgiType_string , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetLogFile(string,string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetLogFile" , "SetLogFile(string,string)" , ZlangInvokeFunction_httpserver_SetLogFile_string_string , ZLANG_OBJECT_void , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.DisableXForwardedFor(bool) */
	func = AddFunctionAndParametersInObject( rt , obj , "DisableXForwardedFor" , "DisableXForwardedFor(bool)" , ZlangInvokeFunction_httpserver_DisableXForwardedFor_bool , ZLANG_OBJECT_void , ZLANG_OBJECT_bool,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetWorkerProcesses(int) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetWorkerProcesses" , "SetWorkerProcesses(int)" , ZlangInvokeFunction_httpserver_SetWorkerProcesses_int , ZLANG_OBJECT_void , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.Run() */
	func = AddFunctionAndParametersInObject( rt , obj , "Run" , "Run()" , ZlangInvokeFunction_httpserver_Run , ZLANG_OBJECT_int , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestIp() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestIp" , "GetHttpRequestIp()" , ZlangInvokeFunction_GetHttpRequestIp , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestMethod() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestMethod" , "GetHttpRequestMethod()" , ZlangInvokeFunction_GetHttpRequestMethod , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestUri() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestUri" , "GetHttpRequestUri()" , ZlangInvokeFunction_GetHttpRequestUri , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestUriPath(int) */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestUriPath" , "GetHttpRequestUriPath(int)" , ZlangInvokeFunction_GetHttpRequestUriPath , ZLANG_OBJECT_string , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequest() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequest" , "GetHttpRequest()" , ZlangInvokeFunction_GetHttpRequest , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestUriParameters() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestUriParameters" , "GetHttpRequestUriParameters()" , ZlangInvokeFunction_GetHttpRequestUriParameters , ZLANG_OBJECT_map , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestPost() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestPost" , "GetHttpRequestPost()" , ZlangInvokeFunction_GetHttpRequestPost , ZLANG_OBJECT_map , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.GetHttpRequestCookies() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestCookies" , "GetHttpRequestCookies()" , ZlangInvokeFunction_GetHttpRequestCookies , ZLANG_OBJECT_map , NULL ) ;
	if( func == NULL )
		return NULL;
	
#if 0
	/* httpserver.GetHttpRequestJson() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetHttpRequestJson" , "GetHttpRequestJson()" , ZlangInvokeFunction_GetHttpRequestJson , ZLANG_OBJECT_map , NULL ) ;
	if( func == NULL )
		return NULL;
#endif
	
	/* httpserver.SetHttpResponse(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetHttpResponse" , "SetHttpResponse(string)" , ZlangInvokeFunction_SetHttpResponse_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetHttpResponseFromFile(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetHttpResponseFromFile" , "SetHttpResponseFromFile(string)" , ZlangInvokeFunction_SetHttpResponseFromFile_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.SetHttpResponseFromHtmlTemplate(string,htmlsection) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetHttpResponseFromHtmlTemplate" , "SetHttpResponseFromHtmlTemplate(string,htmlsection)" , ZlangInvokeFunction_SetHttpResponseFromHtmlTemplate_string_htmlsection , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_htmlsection,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.FormatHttpResponse(string,...) */
	func = AddFunctionAndParametersInObject( rt , obj , "FormatHttpResponse" , "FormatHttpResponse(...)" , ZlangInvokeFunction_FormatHttpResponse_vargs , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_vargs,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.WriteHttpResponseHeader(string,string) */
	func = AddFunctionAndParametersInObject( rt , obj , "WriteHttpResponseHeader" , "WriteHttpResponseHeader(string,string)" , ZlangInvokeFunction_WriteHttpResponseHeader_string_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.WriteHttpResponseCookie(string,string,int) */
	func = AddFunctionAndParametersInObject( rt , obj , "WriteHttpResponseCookie" , "WriteHttpResponseCookie(string,string,int)" , ZlangInvokeFunction_WriteHttpResponseCookie_string_string_int , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_string,NULL , ZLANG_OBJECT_int,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.WriteHttpResponseBody(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "WriteHttpResponseBody" , "WriteHttpResponseBody(string)" , ZlangInvokeFunction_WriteHttpResponseBody_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.FormatWriteHttpResponseBody(...) */
	func = AddFunctionAndParametersInObject( rt , obj , "FormatWriteHttpResponseBody" , "FormatWriteHttpResponseBody(...)" , ZlangInvokeFunction_FormatWriteHttpResponseBody_vargs , ZLANG_OBJECT_bool , ZLANG_OBJECT_vargs,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* httpserver.WriteHttpResponseEnd() */
	func = AddFunctionAndParametersInObject( rt , obj , "WriteHttpResponseEnd" , "WriteHttpResponseEnd()" , ZlangInvokeFunction_WriteHttpResponseEnd , ZLANG_OBJECT_bool , NULL ) ;
	if( func == NULL )
		return NULL;
	
	return obj ;
}

